﻿using Furion.CMS.Core.Base;
using Furion.DataValidation;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Furion.UnifyResult;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Web.Core
{
    /// <summary>
    /// StatusCode风格返回值
    /// </summary>
    [SuppressSniffer, UnifyModel(typeof(SimpleResult<>))]
    public class StatusCodeResultProvider : IUnifyResultProvider
    {
        /// <summary>
        /// 异常返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
        {
            return new JsonResult(Simple(errorMessage: metadata.Errors.ToString()));
        }

        /// <summary>
        /// 成功返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public IActionResult OnSucceeded(ActionExecutedContext context, object data)
        {
            return new JsonResult(Simple(true, data));
        }

        /// <summary>
        /// 验证失败返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
        {
            var errors = metadata.ValidationResult;

            return new JsonResult(Full(errorMessage: "验证失败", data: errors, showType: 4));
        }

        /// <summary>
        /// 特定状态码返回值
        /// <para>
        /// 不更新状态码是为了前端处理服务器返回的401 403状态码请求
        /// </para>
        /// </summary>
        /// <param name="context"></param>
        /// <param name="statusCode"></param>
        /// <param name="unifyResultSettings"></param>
        /// <returns></returns>
        public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
        {
            var responseStatusCode = statusCode;
            var defaultErrorMessage = App.Configuration["FriendlyExceptionSettings:DefaultErrorMessage"] ?? "系统异常，请联系管理员";
            var serializerSettings = App.GetOptions<MvcNewtonsoftJsonOptions>()?.SerializerSettings;

            // 检查返回头中是否包含了 X-SessionSafetyIdentify,包含则说明会话安全标识已过期
            if (context.Response.Headers.TryGetValue("X-SessionSafetyIdentify", out var isSessionSafetyIdentify)
                && isSessionSafetyIdentify == "0")
            {
                // 校正当前请求的返回状态码
                context.Response.StatusCode = responseStatusCode = 401;
            }

            // 根据状态码返回默认消息体
            switch (responseStatusCode)
            {
                // 处理 401 状态码
                case StatusCodes.Status401Unauthorized:
                    await context.Response.WriteAsJsonAsync(Simple(errorMessage: "请先登录！"), serializerSettings);
                    break;
                // 处理 403 状态码
                case StatusCodes.Status403Forbidden:
                    await context.Response.WriteAsJsonAsync(Simple(errorMessage: "对不起，你无权访问该资源"), serializerSettings);
                    break;
                default:
                    await context.Response.WriteAsJsonAsync(Simple(errorMessage: defaultErrorMessage), serializerSettings);
                    break;
            }
        }

        /// <summary>
        /// 返回完整结果
        /// </summary>
        /// <param name="succeeded"></param>
        /// <param name="data"></param>
        /// <param name="errorMessage"></param>
        /// <param name="errorCode"></param>
        /// <param name="host"></param>
        /// <param name="showType"></param>
        /// <param name="traceId"></param>
        /// <returns></returns>
        private static FullResult<object> Full(bool succeeded = default, object data = default, string errorMessage = default, string errorCode = default, string host = default, int showType = default, string traceId = default)
        {
            return new FullResult<object>
            {
                Data = data,
                Success = succeeded,
                ErrorMessage = errorMessage,
                ErrorCode = errorCode,
                Host = host,
                ShowType = showType,
                TraceId = traceId
            };
        }

        /// <summary>
        /// 返回简单结果
        /// </summary>
        /// <param name="succeeded"></param>
        /// <param name="data"></param>
        /// <param name="errorMessage"></param>
        /// <returns></returns>
        private static SimpleResult<object> Simple(bool succeeded = default, object data = default, string errorMessage = default)
        {
            return new SimpleResult<object>
            {
                Data = data,
                Success = succeeded,
                ErrorMessage = errorMessage
            };
        }
    }
}
